package com.imooc.ecommerce.config;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * <h1>自定义异步线程池，异步任务异常捕获处理器</h1>
 * 线程池的设计目的是为了提高系统的性能和效率。
 * 通过预先创建一定数量的核心线程，可以减少线程创建和销毁的开销，提高任务的执行效率
 * 在实际应用中，线程池的大小和核心线程数量通常会根据系统的负载情况进行调整。
 * --如果预计系统会有大量的任务需要处理，可以适当增加线程池的大小和核心线程数量，以提高系统的并发处理能力。
 * --反之，如果系统的负载较轻，可以减少线程池的大小和核心线程数量，以避免资源的浪费
 *
 * @author : huangguangyue
 * @EnableAsync：开启spring 异步任务支持
 * @date : 2024/12/13 11:27
 */
@Slf4j
@EnableAsync
@Configuration
public class AsyncPoolConfig implements AsyncConfigurer {

    /**
     * <h2>将自定义的线程池注入到 Spring 容器中</h2>
     */
    @Bean
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程池大小为 10
        executor.setCorePoolSize(10);
        // 设置最大线程池大小为 20
        executor.setMaxPoolSize(20);
        // 设置任务队列容量为 20
        executor.setQueueCapacity(20);
        // 设置线程空闲时间为 60 秒
        executor.setKeepAliveSeconds(60);
        // 设置线程名称前缀为 "Qinyi-Async-"
        executor.setThreadNamePrefix("Qinyi-Async-");

        // 等待所有任务结果后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 设置等待任务完成的时间为 60 秒
        executor.setAwaitTerminationSeconds(60);
        // 定义拒绝策略，当线程池已满时，新提交的任务将在调用者线程中执行
        executor.setRejectedExecutionHandler(
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
        // 初始化线程池，初始化 core 线程
        executor.initialize();
        return executor;
    }

    /**
     * <h2>指定系统中的异步任务在出现异常时使用到的处理器</h2>
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }

    /**
     * <h2>异步任务异常捕获处理器</h2>
     */
    class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
            throwable.printStackTrace();
            log.error("Async Error: [{}], method: [{}], Param: [{}]",
                    throwable.getMessage(),
                    method.getName(),
                    JSON.toJSONString(objects));
        }
    }
}
